﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using net.xBei.Helper;

namespace net.xBei.WebApi.Repository {
    /// <summary>
    /// 事件管理服务
    /// </summary>
    public class EventService {
        readonly ConcurrentDictionary<string, List<object>> events = new();
        readonly ConcurrentDictionary<string, List<object?>> eventList = new();
        /// <summary>
        /// 
        /// </summary>
        public EventService(ILogger<EventService> logger) {
            this.logger = logger;
            logger.LogInformation(message: "{Datetime} EventService 启动", DateTime.UtcNow);
        }
        private IEnumerable<IEventService>? services = null;

        private readonly ILogger<EventService> logger;
        /// <summary>
        /// 
        /// </summary>
        public IEnumerable<IEventService> Services {
            get {
                if (services != null) return services;
                var tmp = new List<IEventService>();
                foreach (var item in events.Values.SelectMany(i => i)
                                                  .Where(i => i != null)) {
                    try {
                        if (item.GetType().GetProperty("Service")
                                          ?.GetValue(item) is not IEventService es) {
                            continue;
                        }
                        tmp.Add(es);
                    } catch { }
                }
                services = tmp;
                return tmp;
            }
        }

        /// <summary>
        /// 注册事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventHandler"></param>
        /// <returns></returns>
        internal EventService On<T>(Event<T> eventHandler) {
            services = null;
            var list = events.TryGetValue(eventHandler.EventKey, out var tmp) ? tmp : new List<object>();
            list.Add(eventHandler);
            events.TryAdd(eventHandler.EventKey, list);
            logger.LogInformation(message: "EventService 注册 {EventName}（{EventKey}）", eventHandler.Name, eventHandler.EventKey);
            if (eventList.IsEmpty) {
                return this;
            }
            if (!eventList.TryRemove(eventHandler.EventKey, out var list2)) {
                return this;
            }
            logger.LogInformation(message: "EventService {EventName} （{EventKey}）有历史触发", eventHandler.Name, eventHandler.EventKey);
            foreach (var item in list2) {
                try {
                    var data = (T?)item;
                    Task.Run(async () => {
                        await FireAsync(eventHandler.EventKey, data);
                    });
                } catch (Exception ex) {
                    logger.LogError(ex, "EventService 触发 {EventName}（{EventKey}） 失败", eventHandler.Name, eventHandler.EventKey);
                }
            }
            return this;
        }
        /// <summary>
        /// 注册事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventName"></param>
        /// <param name="eventKey"></param>
        /// <param name="handler"></param>
        /// <returns></returns>
        public EventService On<T>(string eventName, string eventKey, Func<T?, Task<bool>> handler)
            => On(new Event<T>(eventName, eventKey, handler));
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventName"></param>
        /// <returns></returns>
        public EventService RemoveEvent(string eventName) {
            if (!events.ContainsKey(eventName)) return this;
            if (!events.TryRemove(eventName, out var list)) {
                return this;
            }
            list?.Clear();
            return this;
        }
        /// <summary>
        /// 注册事件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventKey"></param>
        /// <param name="handler"></param>
        /// <returns></returns>
        public EventService RemoveEvent<T>(string eventKey, Func<T?, bool> handler) {
            if (!events.ContainsKey(eventKey)) return this;
            if (!events.TryGetValue(eventKey, out var list)) {
                return this;
            }
            if (list == null) { return this; }
            foreach (var o in list) {
                if (o is Event<T> e
                    && e.ServiceType == EventServiceType.Function
                    && e.Handler.Equals(handler)) {
                    list.Remove(o);
                    logger.LogInformation("注销事件：{eventName}", eventKey);
                    break;
                }
            }
            if (list.Count == 0) {
                events.TryRemove(eventKey, out var _);
            }
            return this;
        }
        /// <summary>
        /// 事件是否注册
        /// </summary>
        /// <param name="eventKey"></param>
        /// <returns></returns>
        public bool HasRegister(string eventKey) => events.ContainsKey(eventKey);
        /// <summary>
        /// 触发
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="eventKey"></param>
        /// <param name="data">事件要处理的数据（可空）</param>
        public async Task FireAsync<T>(string eventKey, T? data) {
            if (events.TryGetValue(eventKey, out var list)) {
                foreach (var handler in list) {
                    var times = 0;
                    while (times++ < 3) {
                        try {
                            var inc = (Event<T>)handler;
                            var r = await inc.Handler(data);
                            break;
                        } catch (InvalidCastException ex) {
                            logger.LogError(ex, "EventService 触发 {eventName} 失败： 数据类型不匹配，需要：{typeName}",
                                eventKey, handler.GetType().GetProperty("EventDataType")?.GetValue<Type>(handler)?.FullName ?? ex.Message);
                            throw;
                        } catch (Exception ex) {
                            logger.LogError(ex, "EventService 触发 {eventName} [{times}] 失败", eventKey, times);
                            //InvalidOperationException
                            await Task.Delay(300 * times);
                        }
                    }
                }
            } else {
                logger.LogWarning("EventService 触发 {eventName} 失败 -- 没有对应的事件。{data}", eventKey, data?.ToJson());
                //eventList.Enqueue(new KeyValuePair<string, object>(name, data));
                var list2 = eventList.TryGetValue(eventKey, out var tmp) ? tmp : new List<object?>();
                list2.Add(data);
                eventList.TryAdd(eventKey, list2);
            }
        }
    }
    /// <summary>
    /// 事件服务类型
    /// </summary>
    public enum EventServiceType {
        /// <summary>
        /// 函数
        /// </summary>
        Function = 1,
        /// <summary>
        /// 类
        /// </summary>
        Class = 2
    }
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class Event<T> {
        private readonly IEventService? service;
        /// <summary>
        /// 事件处理服务
        /// </summary>
        public IEventService? Service => service;
        public EventServiceType ServiceType { get; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="service"></param>
        /// <param name="handler"></param>
        public Event(IEventService service, Func<T?, Task<bool>> handler) {
            this.service = service;
            Name = service.Name;
            EventKey = service.EventKey;
            Handler = handler;
            ServiceType = EventServiceType.Class;
            EventDataType = typeof(T);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventName"></param>
        /// <param name="eventKey"></param>
        /// <param name="handler"></param>
        public Event(string eventName, string eventKey, Func<T?, Task<bool>> handler) {
            Name = eventName;
            EventKey = eventKey;
            Handler = handler;
            ServiceType = EventServiceType.Function;
            EventDataType = typeof(T);
        }
        public Type EventDataType { get; private set; }
        /// <summary>
        /// 
        /// </summary>
        public Func<T?, Task<bool>> Handler { get; }
        /// <summary>
        /// 事件名称
        /// </summary>
        public string Name { get; }
        /// <summary>
        /// 事件关键字（唯一：机读），用来注册事件
        /// </summary>
        public string EventKey { get; }
    }
    /// <summary>
    /// 事件数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EventData<T> {
        /// <summary>
        /// 数据
        /// </summary>
        public T? Data { get; set; }
        /// <summary>
        /// 参试次数
        /// </summary>
        public int Times { get; set; }
    }
    /// <summary>
    /// 事件处理服务
    /// </summary>
    public interface IEventService {
        /// <summary>
        /// 最大任务数
        /// </summary>
        int MaxThreadCount { get; }
        /// <summary>
        /// 当前任务数量
        /// </summary>
        int ThreadCount { get; }
        /// <summary>
        /// 任务总数
        /// </summary>
        int TaskCount { get; }
        /// <summary>
        /// 事件
        /// </summary>
        string EventKey { get; }
        /// <summary>
        /// 名称
        /// </summary>
        string Name { get; }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        Task SaveQueueAsync();
    }
    /// <summary>
    /// 队列处理事件
    /// </summary>
    /// <typeparam name="T">事件数据</typeparam>
    public abstract class EventQueueBackgroundService<T> : BackgroundService, IEventService {
        private readonly ConcurrentQueue<EventData<T>> queue = new();
        /// <summary>
        /// 队列
        /// </summary>
        protected ConcurrentQueue<EventData<T>> Queue => queue;
        private readonly ConcurrentDictionary<int, Task> tasks = new();
        private readonly ILogger logger;
        /// <summary>
        /// 日志提供器
        /// </summary>
        protected ILogger Logger => logger;
        /// <summary>
        /// 100ms
        /// </summary>
        protected virtual int MillisecondsDelay { get; } = 100;
        /// <summary>
        /// 并行执行数量
        /// 1
        /// </summary>
        public virtual int MaxThreadCount { get; } = 1;
        /// <summary>
        /// 当前任务数量
        /// </summary>
        public int ThreadCount => GetRunningTaskCount();

        /// <summary>
        /// 
        /// </summary>
        public int TaskCount => queue.Count;
        /// <summary>
        /// 错误以后最大重试次数
        /// 3
        /// </summary>
        protected virtual int MaxTryCount { get; } = 3;
        /// <summary>
        /// 事件名称（人读）
        /// </summary>
        public abstract string Name { get; }
        /// <summary>
        /// 事件关键字（唯一：机读），用来注册事件
        /// </summary>
        public abstract string EventKey { get; }
        /// <summary>
        /// 
        /// </summary>
        protected EventService EventService { get; }
        /// <summary>
        /// 
        /// </summary>
        protected bool isRunning = false;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventService"></param>
        /// <param name="logger"></param>
        protected EventQueueBackgroundService(EventService eventService, ILogger logger) {
            EventService = eventService;
            this.logger = logger;
            eventService.On(new Event<T>(this, async (data) => {
                var r = Enqueue(data);
                if (isRunning == false) {
                    isRunning = true;
                    await StartAsync(CancellationToken.None);
                }
                return r;
            }));
            Task.Run(async () => {
                await Task.Delay(100);
                logger.LogInformation("[{Name}]加载任务队列...", Name);
                await ReloadQueueAsync();
                logger.LogInformation("[{Name}]加载任务队列完成", Name);
            });
        }

        /// <inheritdoc/>
        protected async override Task ExecuteAsync(CancellationToken stoppingToken) {
            while (!stoppingToken.IsCancellationRequested && !queue.IsEmpty) {
                var taskList = GetRunningTaskList();
                if (taskList.Count() >= MaxThreadCount) {
                    await Task.WhenAny(taskList);
                    taskList = GetRunningTaskList();
                    await Task.Delay(MillisecondsDelay, stoppingToken);
                }
                if (queue.TryDequeue(out var data)) {
                    var t = Task.Run(async () => { await FireAsync(data); }, stoppingToken);
                    RunTask(t);
                }
                await Task.Delay(MillisecondsDelay, stoppingToken);
            }
            isRunning = false;
        }
        int GetRunningTaskCount() {
            var c = 0;
            foreach (var i in tasks) {
                if (i.Value == null || i.Value.IsCompleted) continue;
                c++;
            }
            return c;
        }
        IEnumerable<Task> GetRunningTaskList() {
            var list = new List<Task>();
            foreach (var i in tasks) {
                if (i.Value == null || i.Value.IsCompleted) continue;
                list.Add(i.Value);
            }
            return list;
        }
        void RunTask(Task task) {
            foreach (var i in tasks) {
                if (i.Value == null || i.Value.IsCompleted) {
                    tasks[i.Key] = task;
                    return;
                };
            }
            tasks.TryAdd(tasks.Count, task);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public virtual async Task ReloadQueueAsync() {
            await Task.Delay(0);
        }
        /// <summary>
        /// 系统停止的时候保存队列
        /// </summary>
        /// <returns></returns>
        public virtual async Task SaveQueueAsync() {
            await Task.Delay(0);
        }
        /// <inheritdoc/>
        public override async Task StopAsync(CancellationToken cancellationToken) {
            logger.LogInformation("[{Name}]停止监听...", Name);
            if (!queue.IsEmpty) {
                //保存队列
                logger.LogInformation("[{Name}]保存任务队列", Name);
                await SaveQueueAsync();
            }
            logger.LogInformation("[{Name}]停止监听", Name);
            await base.StopAsync(cancellationToken);
        }
        /// <summary>
        /// 触发事件
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        protected abstract Task FireAsync(EventData<T> data);
        /// <summary>
        /// 事件入队
        /// </summary>
        /// <param name="data">事件需要的数据（可空）</param>
        /// <returns></returns>
        protected virtual bool Enqueue(T? data) {
            queue.Enqueue(new EventData<T> { Data = data, Times = 0 });
            return true;
        }
        /// <summary>
        /// 事件重试
        /// </summary>
        /// <param name="eventData"></param>
        /// <returns></returns>
        protected async Task RetryAsync(EventData<T> eventData) {
            eventData.Times++;
            if (eventData.Times >= MaxTryCount) return;
            await Task.Delay(MillisecondsDelay * eventData.Times);
            queue.Enqueue(eventData);
            if (isRunning == false) {
                isRunning = true;
                _ = StartAsync(CancellationToken.None);
            }
        }
    }
    /// <summary>
    /// 事件数据
    /// </summary>
    public interface IEventData { }
    /// <summary>
    /// 空数据
    /// </summary>
    public class EmptyEvent : IEventData { }
}
